home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 40
/
Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso
/
Aminet
/
dev
/
src
/
xad_DImp.lha
/
DImp.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-08-20
|
11KB
|
392 lines
/* Disk Imploder (DImp) disk archiver client for XAD.
* Copyright (C) 2000 Stuart Caie <kyzer@4u.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This XAD client reads DImp disk files, either normal data files
* or ones with executable headers (1.00 and 2.27 headers known),
* and writes them out as ADF files, or allows them to be written
* to standard Amiga formatted disks.
* The DImp format is (C) 1988-1991 Albert-Jan Brouwer
*
* $VER: DImp.c 1.2 (20.08.2000)
*/
#include <exec/memory.h>
#include <libraries/xadmaster.h>
#include <proto/xadmaster.h>
#include "SDI_compiler.h"
#include "ConvertE.c"
#ifndef XADMASTERFILE
#define DImp_Client FirstClient
#define NEXTCLIENT NULL
const UBYTE version[] = "$VER: DImp 1.2 (20.08.2000)";
#endif
#define DIMP_VERSION 1
#define DIMP_REVISION 2
#define XADBASE REG(a6, struct xadMasterBase *xadMasterBase)
/* work-doing macros */
#define SKIP(offset) if ((err = xadHookAccess(XADAC_INPUTSEEK, \
(ULONG)(offset), NULL, ai))) goto exit_handler
#define READ(buffer,length) if ((err = xadHookAccess(XADAC_READ, \
(ULONG)(length), (APTR)(buffer), ai))) goto exit_handler
#define WRITE(buffer,length) if ((err = xadHookAccess(XADAC_WRITE, \
(ULONG)(length), (APTR)(buffer), ai))) goto exit_handler
#define COPY(length) if ((err = xadHookAccess(XADAC_COPY, \
(ULONG)(length), NULL, ai))) goto exit_handler
#define ALLOC(t,v,l) if (!((v) = (t) xadAllocVec((l),MEMF_CLEAR))) \
ERROR(NOMEMORY)
#define ALLOCOBJ(t,v,kind,tags) \
if (!((v) = (t) xadAllocObjectA((kind),(tags)))) ERROR(NOMEMORY)
#define FREE(obj) xadFreeObjectA((APTR)(obj),NULL)
#define ERROR(error) do { err = XADERR_##error; goto exit_handler; } while(0)
#define DIMP_CYLSIZE (2*11*512)
/* DImp's info-table */
#define dinf_cksum (0) /* ULONG checksum */
#define dinf_compmode (4) /* UWORD compression_mode */
#define dinf_bitmap (6) /* UBYTE disk_bitmap[10] */
#define dinf_ctable1 (16) /* UBYTE compression_table1[28] */
#define dinf_ctable2 (44) /* UBYTE compression_table2[28] */
#define dinf_textplen (72) /* ULONG textmsg_packed_len */
#define dinf_textulen (76) /* ULONG textmsg_unpacked_len */
#define dinf_textcksum (80) /* ULONG textmsg_checksum */
#define dinf_cylinfo (84) /* ULONG cylinder_info[80] */
#define dinf_SIZEOF (404) /* ...maximum length */
int DImp_bitmap(UBYTE *info, int track) {
return info[dinf_bitmap + (track>>3)] & (1 << (7-(track&7)));
}
ULONG DImp_checksum(UBYTE *data, ULONG len) {
ULONG cksum = 0;
while (len > 1) {
cksum += EndGetM16(data);
data += 2; len -= 2;
}
if (len) cksum += (*data << 8);
return (cksum+7) & 0xFFFFFFFF;
}
/* de-implosion */
/* add.b d3,d3; bne gotbit; move.b -(a3),d3; addx.b d3,d3; gotbit: */
#define GETBIT do { \
bit = bitbuf & 0x80; bitbuf <<= 1; \
if (!bitbuf) { bit2 = bit; bitbuf = *--inp; bit = bitbuf & 0x80; \
bitbuf <<= 1; if (bit2) bitbuf++; }; \
} while (0)
static UBYTE explode_tab1[] = { 6, 10, 10, 18 };
static UBYTE explode_tab2[] = { 1, 1, 1, 1, 2, 3, 3, 4, 4, 5, 7, 14 };
int DImp_explode(UBYTE *buf, UBYTE *table, ULONG inlen, ULONG outlen) {
UBYTE *inp = buf + inlen-5;
UBYTE *outp = buf + outlen;
UBYTE *rep, bitbuf, bit, bit2;
ULONG litlen, matchlen, x, y, z;
if (inlen & 1) {
bitbuf = inp[4];
litlen = EndGetM32(inp);
}
else {
bitbuf = inp[0];
litlen = EndGetM32(inp+1);
}
while (1) {
if (outp-litlen < buf) return 0;
while (litlen--) *--outp = *--inp;
/* main exit point - after the literal copy */
if (outp <= buf) break;
GETBIT; if (bit) {
GETBIT; if (bit) {
GETBIT; if (bit) {
GETBIT; if (bit) {
matchlen = 0;
GETBIT; if (bit) {
x = 3;
matchlen = *--inp - 1;
}
else {
x = 3;
matchlen <<= 1; GETBIT; if (bit) matchlen++;
matchlen <<= 1; GETBIT; if (bit) matchlen++;
matchlen <<= 1; GETBIT; if (bit) matchlen++;
matchlen += 5;
}
} else x=3, matchlen=4;
} else x=2, matchlen=3;
} else x=1, matchlen=2;
} else x=0, matchlen=1;
y = 0;
z = x;
GETBIT; if (bit) {
GETBIT; if (bit) {
y = explode_tab1[x];
x += 8;
}
else {
y = 2;
x += 4;
}
}
x = explode_tab2[x];
litlen = 0;
while (x--) { litlen<<=1; GETBIT; if (bit) litlen++; }
litlen += y;
rep = outp + 1;
x = z;
GETBIT; if (bit) {
z <<= 1; GETBIT;
if (bit) { rep += EndGetM16(table+z+8); x += 8; }
else { rep += EndGetM16(table+z); x += 4; }
}
x = table[x+16];
y = 0;
while (x--) { y<<=1; GETBIT; if (bit) y++; }
rep += y;
if (outp-matchlen < buf) return 0;
do { *--outp = *--rep; } while (matchlen--);
}
/* return 1 if we used up all input bytes (as we should) */
return (inp == buf);
}
ASM(BOOL) DImp_RecogData(REG(d0, ULONG size), REG(a0, UBYTE *d), XADBASE) {
ULONG infolen;
if (d[0]!='D' || d[1]!='I' || d[2]!='M' || d[3]!='P') return 0;
infolen = EndGetM32(d+4);
return (BOOL) (infolen > 4 && infolen <= dinf_SIZEOF);
}
ASM(LONG) SAVEDS DImp_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
UBYTE buffer[8], *info, *text;
ULONG infolen, textplen, textulen;
struct xadDiskInfo *di = NULL;
struct xadTextInfo *ti;
LONG err = XADERR_OK;
int x;
ALLOCOBJ(struct xadDiskInfo *, di, XADOBJ_DISKINFO, NULL);
ai->xai_DiskInfo = di;
di->xdi_EntryNumber = 1;
di->xdi_SectorSize = 512;
di->xdi_TotalSectors = 80 * 22;
di->xdi_Cylinders = 80;
di->xdi_CylSectors = 22;
di->xdi_Heads = 2;
di->xdi_TrackSectors = 11;
/* read "DIMP" and info table length */
READ(buffer, 8);
infolen = EndGetM32(buffer+4);
/* allocate and read info table */
ALLOC(UBYTE *, info, dinf_SIZEOF);
ai->xai_PrivateClient = (APTR) info;
READ(info, infolen);
/* info table checksum */
if (EndGetM32(info+dinf_cksum) != DImp_checksum(info+4, infolen-4))
ERROR(CHECKSUM);
/* look for start and end cylinders */
for (x=0; x<80; x++) if (DImp_bitmap(info, x)) break;
di->xdi_LowCyl = x;
if (x == 80) ERROR(EMPTY);
for (x=79; x>=0; x--) if (DImp_bitmap(info, x)) break;
di->xdi_HighCyl = x;
textplen = EndGetM32(info+dinf_textplen);
textulen = EndGetM32(info+dinf_textulen);
di->xdi_Flags = XADDIF_SEEKDATAPOS;
di->xdi_DataPos = ai->xai_InPos + textplen;
if (textulen) {
ALLOCOBJ(struct xadTextInfo *, ti, XADOBJ_TEXTINFO, NULL);
ALLOC(UBYTE *, text, (ti->xti_Size = textulen)+1);
di->xdi_TextInfo = ti;
ti->xti_Text = text;
READ(text, textplen);
text[textulen] = 0;
if (textulen != textplen && !DImp_explode(text, info+dinf_ctable1,
textplen, textulen)) ERROR(DECRUNCH);
}
exit_handler:
if (err) {
if (!di) return err;
ai->xai_Flags |= XADAIF_FILECORRUPT;
ai->xai_LastError = err;
}
return XADERR_OK;
}
ASM(LONG) SAVEDS DImp_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
UBYTE *buf = NULL, *info = (UBYTE *) ai->xai_PrivateClient, *p;
struct xadDiskInfo *di = ai->xai_CurDisk;
ULONG cyl, x;
LONG err;
ALLOC(UBYTE *, buf, DIMP_CYLSIZE);
for (cyl = di->xdi_LowCyl; cyl <= ai->xai_HighCyl; cyl++) {
if (cyl >= ai->xai_LowCyl) {
/* extracting */
/* clear the buffer */
p=buf; x=DIMP_CYLSIZE; while (x--) *p++ = 0;
if (DImp_bitmap(info, cyl)) {
x = EndGetM32(info+dinf_cylinfo+(cyl<<2));
if (x != 0xFFFFFFFF && x != 0) {
UWORD length = x >> 16;
if (length > DIMP_CYLSIZE) ERROR(INPUT);
READ(buf, length);
if ((DImp_checksum(buf, length) & 0xFFFF) != (x & 0xFFFF))
ERROR(CHECKSUM);
if (length != DIMP_CYLSIZE && !DImp_explode(buf,
info+dinf_ctable2, length, DIMP_CYLSIZE)) ERROR(DECRUNCH);
}
}
WRITE(buf, DIMP_CYLSIZE);
}
else {
/* skipping */
if (DImp_bitmap(info, cyl)) {
x = EndGetM32(info+dinf_cylinfo+(cyl<<2));
if (x != 0xFFFFFFFF && x != 0) SKIP(x >> 16);
}
}
}
exit_handler:
if (buf) FREE(buf);
return err;
}
ASM(void) DImp_Free(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
if (ai->xai_PrivateClient) {
FREE(ai->xai_PrivateClient);
ai->xai_PrivateClient = NULL;
}
}
#define HUNK_HEADER 1011
#define HUNK_CODE 1001
ASM(BOOL) DImpSFX_RecogData(REG(d0, ULONG size), REG(a0, UBYTE *d), XADBASE) {
ULONG i;
if (size < 32
|| EndGetM32(d) != HUNK_HEADER
|| EndGetM32(d+24) != HUNK_CODE) return 0;
/* specific cases: DImp 1.00 = 3856; DImp 2.27 = 5796 */
if ((size >= 3860 && EndGetM32(d+3856) == 0x44494D50)
|| (size >= 5800 && EndGetM32(d+5796) == 0x44494D50)) return 1;
/* generic case - look just past the code hunk */
for (i = (EndGetM32(d+28)<<2) + 36; i < size; i+=4) {
if (EndGetM32(d+i) == 0x44494D50) return 1;
}
return 0;
}
ASM(LONG) DImpSFX_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
ULONG readlen, offset = 0, i;
UBYTE *buf;
LONG err;
readlen = ai->xai_InSize;
if (readlen > 6144) readlen = 6144;
ALLOC(UBYTE *, buf, readlen);
READ(buf, readlen);
for (i = (EndGetM32(buf+28)<<2) + 36; i < readlen; i+=4) {
if (EndGetM32(buf+i) == 0x44494D50) { offset = i; break; }
}
err = XADERR_DATAFORMAT;
exit_handler:
if (buf) FREE(buf);
/* if we found a match, actually look at the archive */
if (offset != 0) {
SKIP(offset - ai->xai_InPos);
err = DImp_GetInfo(ai, xadMasterBase);
}
return err;
}
const struct xadClient DImpSFX_Client = {
NEXTCLIENT, XADCLIENT_VERSION, 4, DIMP_VERSION, DIMP_REVISION,
6144, XADCF_DISKARCHIVER|XADCF_FREEDISKINFO|XADCF_NOCHECKSIZE,
0, "DImp SFX",
(BOOL (*)()) DImpSFX_RecogData,
(LONG (*)()) DImpSFX_GetInfo,
(LONG (*)()) DImp_UnArchive,
(void (*)()) DImp_Free
};
const struct xadClient DImp_Client = {
(struct xadClient *) &DImpSFX_Client, XADCLIENT_VERSION, 4,
DIMP_VERSION, DIMP_REVISION,
10, XADCF_DISKARCHIVER|XADCF_FREEDISKINFO,
0, "DImp",
(BOOL (*)()) DImp_RecogData,
(LONG (*)()) DImp_GetInfo,
(LONG (*)()) DImp_UnArchive,
(void (*)()) DImp_Free
};